/**
  @file TicTacToeGameController.hpp
  @author Hanna Dutkiewicz
*/

#ifndef TICTACTOEGAMECONTROLLER_H
#define TICTACTOEGAMECONTROLLER_H

#include <QObject>
#include <QFutureWatcher>

#include <boost/shared_ptr.hpp>
#include <boost/random.hpp>

#include "../game-strategy-library/GameStrategy.hpp"
#include "../game-strategy-library/Player.hpp"
#include "../game-strategy-library/AbstractGameFactory.hpp"

#include "TicTacToeGameFactory.hpp"
#include "gamewindow.hpp"
#include "TicTacToePlayer.hpp"
#include "gameboard.hpp"
#include "TicTacToeMove.hpp"
#include "BaseGameBoard.hpp"


/**
	@class GameController
	@author Hanna Dutkiewicz
	TicTacToe game controller (in MVC model)
*/
class TicTacToeGameController: public QObject{

	Q_OBJECT

public:
	/**
		Constructor of a game controller linked with a specific game window
		@param gameWindow window of the game
	*/
	TicTacToeGameController(GameWindow &gameWindow);

	/**
		A destructor
	*/
	~TicTacToeGameController();

	/**
		Initializes all elements in a game controller.
		Creates and sets graphics scene to GUI elements,
		creates appropriate game factory,
		initializes game board and game strategy,
		makes connects with elements of the GUI
	*/
	void initialize();

	/**
		Creates new game,
		method to be binded and executed in a new thread
		@return pointer to a new game
	*/
	boost::shared_ptr<library::Game> toBindOnlyCreateGame();

	/**
		Creates new game and "trains" oponent,
		method to be binded and executed in a new thread
		@return pointer to a new game
	*/
	boost::shared_ptr<library::Game> toBindCreateGameAndTrain();

	/**
		Saves current game,
		method to be binded and executed in a new thread
		@param filename name of the file to save to
	*/
	void toBindSaveGame(std::string filename);

	/**
		Loads and starts a new game,
		method to be binded and executed in a new thread
		@param filename name of the file with a game to load
	*/
	void toBindLoadGame(std::string filename);

/*********** SLOTS ***************/
public slots:

	/**
		Slot connected to a signal generated by game window to save the game
		@param filename name of the file to be saved to
	*/
	void saveGameSlot(std::string filename);

	/**
		Creates just another game in a set of games. 
		Starts the game with the same properties: sign and oponent.
	*/
	void createNewGameSlot();

	/**
		Slot connected to game window to create totally new set of games, 
		with a new generated oponent of specific level
		@param humanPlayerSign sign of human player
		@param computerPlayerLevel level of computer player
	*/
	void createFirstGameNewPlayerSlot
		(TicTacToePlayer::PlayerSign humanPlayerSign, TicTacToePlayer::PlayerLevel computerPlayerLevel);

	/**
		Slot connected to a signal generated by game window to create totally new set of games, 
		with a loaded state of play (oponent)
		@param humanPlayerSign sign of human player
		@param filename name of the game state to be loaded
	*/
	void createFirstGameLoadPlayerSlot
		(TicTacToePlayer::PlayerSign humanPlayerSign, std::string filename);

	/**
		Slot connected to a signal generated by game window when a human player made a move
		@param coords coordinates of a field on which player made a move
	*/
	void playerMadeAmoveSlot(std::pair<int,int> coords);

	/**
		Slot connected to a signal generated by game window when player changes its sign
		@param humanPlayerSign new human player sign
	*/
	void changeSignSlot(TicTacToePlayer::PlayerSign humanPlayerSign);

	/**
		Slot connected to a signal finished() generated by threads 
		that creates and trains new games,
		starts a new game with created "oponent" - game state
	*/
	void startNewGame();

	/**
		Starts a new loaded game
	*/
	void startNewLoadedGame();

	/**
		Notifies elements that game was saved
	*/
	void gameSaved();

private:

	/**
		Makes computer move on a board,
		finds a move to make by calling findBestMove() from game strategy
	*/
	void makeComputerMove();

	/**
		Checks if a game was finished and if it was - notifies all elements
		that should know about it: game board, game window and game strategy
		@param coordinated coordinates of a move that was made
		@param player which player's turn was it
		@param board game board to notify about a move
		@param notifyWindow whether to notify game window about a move (if it's a training game then GUI isn't involved in a game)
		@return <code>true</code> if a game was finished, <code>false</code> otherwhise
	*/
	bool checkEndGame
		(std::pair<int,int> coordinates, boost::shared_ptr<library::Player> player, BaseGameBoard & board, bool notifyWindow);

	/**
		Trains computer player, that is train game tree by using game strategy,
		uses computerPlayerLevel_ field to check what level should a trained game has
		@param game a pointer to game which should be "trained"
		@return pointer to a approprietly trained game
	*/
	boost::shared_ptr<library::Game> trainComputerPlayer(boost::shared_ptr<library::Game> game);

	/**
		Returns a random move from available moves
		@return a random move from available ones
	*/
	boost::shared_ptr<library::Move> getRandMove();

	/**
		Creates players
		@param humanPlayerSign sign of the human player
	*/
	void createPlayers(TicTacToePlayer::PlayerSign humanPlayerSign);

	/**
		Displays percentage of visited nodes in a game tree
	*/
	void setPercentageOnWindow();

/******* PRIVATE FIELDS *********/
// model
	/** Game strategy, from the library*/
	library::GameStrategy gameStrategy_;

	/** A pointer to a game factory to create games and serialize/deserialize then */
	boost::shared_ptr<library::AbstractGameFactory> factory_;

// view
	/** Game window */
	GameWindow &gameWindow_;

// game elements
	/** Game board */
	GameBoard gameBoard_;
	/** Pointer to a human player */
	boost::shared_ptr<library::Player> playerHuman_;
	/** Pointer to a computer player */
	boost::shared_ptr<library::Player> playerComp_;

	/** Watcher of threads running with a function to create a game tree and train it */
	QFutureWatcher<boost::shared_ptr<library::Game> > watcher_;

	/** Watcher for threads running with function to load/save game */
	QFutureWatcher<void > serWatcher_;

	/** Holds computer player level */
	TicTacToePlayer::PlayerLevel computerPlayerLevel_;

	/** How many nodes should be at least visited in a game tree to say that a computer player has intermediate level */
	static const int NODES_MEDIUM = 100000;
	/** How many nodes should be at least visited in a game tree to say that a computer player has advanced level */
	static const int NODES_ADVANCED = 300000;

};


#endif /* TICTACTOEGAMECONTROLLER_H */
